function Calendar(id,x,y,position,sid)
{
	this.InitValidator=function()
	{
		if(window.Validators)
			Validators[Validators.length]=this;
	}
	this.InitValidator();
	this.Type="Calendar";
	this.Date=null;         //Day and Month are 1 based
	this.RenderDate=null;   //Day and Month are 0 based
	var today=new Date();

	var Calendar;
	var MonthMenuPanel;
	var YearMenuPanel;

	var popup;
	var monthPopup;
	var yearPopup;
	var ve;
	var Textbox;
	this.Validator;
	this.DayHeadings=['Mon','Tue','Wed','Thu','Fri','Sat','Sun'];
	this.MonthNames=['January','February','March','April','May','June','July','August','September','October','November','December'];
	this.ShortMonthNames=['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
	this.DaysInMonth=[31,-1,31,30,31,30,31,31,30,31,30,31];
	this.Format = 'dd-MMM-yyyy';
	this.TimeFormat = 'dd-MMM-yyyy hh:mm:ss';
	this.StartYear=null;
	this.YearCols=5;
	this.YearsInDropDown=25;
	this.MinDate=null;
	this.MaxDate=null;
	this.MinCal=null;
	this.MaxCal=null;
	this.OnDateChanged=null;
	this.FirstShow=true;
	this.Required=false;
	this.Follow=true;
	this.Disabled=false;
	var AscImg=ImageUrl('Asc.gif');
	var DescImg=ImageUrl('Desc.gif');
	var CloseImg=ImageUrl('CloseSmall.gif');
	var CalendarDownImg=ImageUrl('CalendarDown.gif');
	var CalendarLeftImg=ImageUrl('CalendarLeft.gif');
	var CalendarRightImg=ImageUrl('CalendarRight.gif');
	this.Init=function()
	{
		ve=el(id+'_value');
		Textbox=el(id+'_tb');


		popup=new PopupMenu(id+'_Calendar',x,y,position);
		monthPopup=new PopupMenu(id+'_MonthMenuPanel',0,0,'b');
		yearPopup=new PopupMenu(id+'_YearMenuPanel',0,0,'bc');

		if(Textbox)
		{
			Textbox.value='';
			if(this.Date)
			{
				this.SetDate(this.Date.Day-1,this.Date.Month-1,this.Date.Year,true);
			}
			Textbox.disabled=this.Disabled;
		}
	}
	this.Init();
	this.PadZero=function(n)
	{
		return (n<10)?('0'+n):n;
	}
	this.GetFormatString = function(date, t) {
		if (!date)
			return '';
		var d = date.Day;
		var M = date.Month;
		var y = date.Year;
		var h = date.Hour;
		var m = date.Minute;
		var s = date.Second;

		var f = this.Format;
		if (t)
			f = this.TimeFormat;
		f = f.replace('dd', '#a#');
		f = f.replace('d', '#b#');
		f = f.replace('MMMM', '#c#');
		f = f.replace('MMM', '#d#');
		f = f.replace('MM', '#e#');
		f = f.replace('M', '#f#');
		f = f.replace('yyyy', '#g#');
		f = f.replace('yy', '#h#');

		f = f.replace('hh', '#i#');
		f = f.replace('h', '#j#');
		f = f.replace('mm', '#k#');
		f = f.replace('m', '#l#');
		f = f.replace('ss', '#m#');
		f = f.replace('s', '#n#');

		f = f.replace('#a#', this.PadZero(d));
		f = f.replace('#b#', d);
		f = f.replace('#c#', this.MonthNames[M - 1]);
		f = f.replace('#d#', this.ShortMonthNames[M - 1]);
		f = f.replace('#e#', this.PadZero(M));
		f = f.replace('#f#', M);
		f = f.replace('#g#', y);
		f = f.replace('#h#', this.PadZero(y % 100));

		f = f.replace('#i#', this.PadZero(h));
		f = f.replace('#j#', h);
		f = f.replace('#k#', this.PadZero(m));
		f = f.replace('#l#', m);
		f = f.replace('#m#', this.PadZero(s));
		f = f.replace('#n#', s);

		return f;
	}
	this.CompareDates=function(d1,d2)
	{
		if(!d2||!d2)
			return null;
		var _d1=new Date();
		var _d2=new Date();
		_d1.setFullYear(d1.Year,d1.Month-1,d1.Day-1);
		_d2.setFullYear(d2.Year,d2.Month-1,d2.Day-1);
		if(_d1<_d2)
			return -1;
		if(_d1>_d2)
			return 1;
		return 0;
	}
	this.ConvertDate=function(jd)
	{
		var dt=new Object();
		dt.Day=jd.getDate();
		dt.Month=jd.getMonth()+1;
		dt.Year=jd.getFullYear();
		return dt;
	}
	this.SetDate=function(d,m,y,init)
	{
		if(!init&&Textbox.disabled)
			return;
		var dt=new Object();
		if(m==null)
			m=this.RenderDate.Month;
		if(y==null)
			y=this.RenderDate.Year;
		if(d!=null)
			dt.Day=d+1;		//Convert from 0 based day
		if(m!=null)
			dt.Month=m+1;	//Convert from 0 based month
		if(y!=null)
			dt.Year=y;
		if(this.MinDate&&(this.CompareDates(dt,this.MinDate)==-1))
			return;
		if(this.MaxDate&&(this.CompareDates(dt,this.MaxDate)==1))
			return; 
		if(this.MinCal&&this.MinCal.Date&&(this.CompareDates(dt,this.MinCal.Date)==-1))
			return;
		if(this.MaxCal&&this.MaxCal.Date&&(this.CompareDates(dt,this.MaxCal.Date)==1))
			return;
		this.Date=dt;
		if(sid)
			SaveSession(sid,dt);
		ve.value='{Day:'+dt.Day+',Month:'+dt.Month+',Year:'+dt.Year+'}'
		Textbox.value=this.GetFormatString(dt);
		this.Hide();
		if(this.OnDateChanged&&!init)
		eval(this.OnDateChanged);
	}
	this.SetRenderMonth=function(m)
	{
		monthPopup.Hide();
		if(m==null)
			return;
		var y=this.RenderDate.Year;
		if(m<0)
		{
			m=11;
			y=(y-1);
		}
		if(m>11)
		{
			m=0;
			y=(y+1);
		}
		this.RenderDate.Month=m;
		this.RenderDate.Year=y;
		this.Render();
	}
	this.SetRenderYear=function(y)
	{
		yearPopup.Hide();
		if(y==null)
			return;
		this.RenderDate.Year=y;
		this.StartYear=y-parseInt(this.YearsInDropDown/2);
		this.Render();
	}
	this.GetDaysInMonth=function(m,y)
	{
		if(m<0)
		{
			m=11;
			y=(y-1);
		}
		if(m==1)
		{
			if((y%4)==0)
				return 29
			return 28;
		}
		return this.DaysInMonth[m];
	}
	this.GetFirstOfMonthDayIndex=function()
	{
		var d=new Date();
		d.setFullYear(this.RenderDate.Year,this.RenderDate.Month,1);
		var idx=(d.getDay()-1);
		if(idx==-1)
			idx=6;
		return idx;
	}
	this.IsDateSelectable=function(dt)
	{
		var r=new Object();
		r.Title='Click to Select this date.';
		r.Clickable=true;
		if(dt==null)
			return false;
		if(this.MinDate&&(this.CompareDates(dt,this.MinDate)==-1))
		{
			r.Title='Min date: '+this.GetFormatString(this.MinDate);
			r.Clickable=false;
		}
		if(this.MinCal&&this.MinCal.Date&&(this.CompareDates(dt,this.MinCal.Date)==-1))
		{
			r.Title='Min date: '+this.GetFormatString(this.MinCal.Date);
			r.Clickable=false;
		}
		if(this.MaxDate&&(this.CompareDates(dt,this.MaxDate)==1))
		{
			r.Title='Max date: '+this.GetFormatString(this.MaxDate);
			r.Clickable=false;
		}
		if(this.MaxCal&&this.MaxCal.Date&&(this.CompareDates(dt,this.MaxCal.Date)==1))
		{
			r.Title='Max date: '+this.GetFormatString(this.MaxCal.Date);
			r.Clickable=false;
		}
		return r;
	}
	this.RenderDay=function(d,o)
	{
		var html=''
		var dt=this.Date;
		var rd=this.RenderDate;
		var s=false;
		var title=''
		if(dt&&rd&&!o)
			s=(rd.Month==dt.Month-1)&&(rd.Year==dt.Year)&&(d==dt.Day-1);
		var css='CalendarDay';
		var cssna='CalendarDayUnavailable';
		if(s)
			css+='Selected';
		else if(o)
			css+='OtherMonth';
		var click='onclick='+id;
		if(!o)
		{
			var _td=new Object();
			var noclick=false;
			_td.Day=d+1;
			_td.Month=this.RenderDate.Month+1;
			_td.Year=this.RenderDate.Year;
			var ids=this.IsDateSelectable(_td); 
			title=ids.Title;
			if(ids.Clickable)
			{
				click+='.SetDate('+d+');';
			}
			else
			{
				css=cssna;
				click='';
			}
			if(!s&&this.CompareDates(this.ConvertDate(today),_td)==0)
				css="CalendarDayToday";
		}
		else
		{
			var om=this.RenderDate.Month;
			if(d<7)
			{
				title='Show Next Month';
				om=(om+1);
			}
			else
			{
				title='Show Previous Month';
				om=(om-1);
			}
			click+='.SetRenderMonth('+om+');'
		}

		html+='<td class="'+css+'" '+click+' title="'+title+'" >'+(d+1)+'</td>'
		return html;
	}
	this.RenderDayHeadings=function()
	{
		var html='';
		html+='<tr>';
		var dh=this.DayHeadings;
		for(var i=0;i<dh.length;i++)
			html+='<td class="CalendarDayHeading">'+dh[i]+'</td>';
		html+='</tr>';
		return html;
	}
	this.RenderMonth=function()
	{
		var html=''
		html+='<div class="CalendarContent">';
		html+='<table cellspacing="0" class="DateTable">';
		html+=this.RenderDayHeadings();
		var dim=this.GetDaysInMonth(this.RenderDate.Month,this.RenderDate.Year);
		var dipm=this.GetDaysInMonth(this.RenderDate.Month-1,this.RenderDate.Year);
		var fdmi=this.GetFirstOfMonthDayIndex();
		var cur=0;
		var next=0;
		var other=false;
		for(var i=0;i<6;i++)
		{
			html+='<tr>';
			for(var j=0;j<7;j++)
			{
				var day=cur;
				if(fdmi>0)
				{
					day=dipm-fdmi;
					fdmi--;
					other=true;
				}
				else
				{
					if(cur>=dim)
					{
						day=next;
						next++;
						other=true;
					}
					else
					{
						cur++;
						other=false;
					}
				}
				html+=this.RenderDay(day,other);
			}
			html+='</tr>';
			if(next>0)
				break;
		}
		html+='</table>';
		html+='</div>';
		return html;
	}
	this.ShowMonthMenu=function(o)
	{
		if(MonthMenuPanel==null)
		{
			var mid=id+'_MonthMenuPanel';
			var MonthMenuPanel=Append('div',mid,'PopupMenuPanel MonthMenuPanel');

			var html='';
			/*
			html+='<div class="PopupMenu CalendarMonthMenu" >';
			for(var i=0;i<this.MonthNames.length;i++)
				html+='<div class="MenuItem" onclick="'+id+'.SetRenderMonth('+i+');">'+this.MonthNames[i]+'</div>';
			html+='</div>';
			*/

			html+='<table cellspacing="0" class="PopupMenu" >';
			var hl=(this.MonthNames.length/2)
			for(var i=0;i<hl;i++)
			{
				html+='<tr>';
				html+='<td class="MenuItem" onclick="'+id+'.SetRenderMonth('+i+');">'+this.MonthNames[i]+'</td>';
				html+='<td class="MenuItem" onclick="'+id+'.SetRenderMonth('+(i+hl)+');">'+this.MonthNames[i+hl]+'</td>';
				html+='</tr>';
			}
			html+='</table>';

			MonthMenuPanel.innerHTML=html;
		}
		monthPopup.ShowFromNewSource(o);
	}
	this.ModifyStartYear=function(dx)
	{
		var nsy=this.StartYear+dx;
		var ney=nsy+this.YearsInDropDown;
		if(this.MinDate&&ney<=this.MinDate.Year)
			return;
		if(this.MaxDate&&nsy>this.MaxDate.Year)
			return;
		this.StartYear=nsy;
		this.ShowYearMenu(el(id+'_year_sel'),true);
	}
	this.ShowYearMenu=function(o, r)
	{
		if(YearMenuPanel==null)
		{
			var mid=id+'_YearMenuPanel';
			YearMenuPanel=Append('div',mid,'PopupMenuPanel YearMenuPanel');
		}
		var html='';
		html+='<div class="PopupMenu CalendarYearMenu" >';
		var yid=this.YearsInDropDown;
		html+='<div class="MenuItem CalendarYearMenuUp" onclick="'+id+'.ModifyStartYear(-'+yid+');" style="text-align:center;">'+ImageHtml(DescImg)+'</div>';
		var col=0;
		var sl=true;
		html+='<table cellspacing="0" >'
		for(var i=0;i<yid;i++)
		{
			var _y=this.StartYear+i;
			if(sl)
			{
				html+='<tr>';
				sl=false;
			}

			html+='<td class="MenuItem CalendarYearItem" onclick="'+id+'.SetRenderYear('+_y+');">';
			if(this.RenderDate&&this.RenderDate.Year==_y)
				html+='<b>'+_y+'</b>';
			else
				html+=_y;
			html+='</td>';
			col++;
			if(col>=this.YearCols)
			{
				html+='</tr>';
				col=0;
				sl=true;
			}
		}
		html+='</table>';
		html+='<div class="CalendarYearMenuDown MenuItem" onclick="'+id+'.ModifyStartYear('+yid+');"  style="text-align:center;">'+ImageHtml(AscImg)+'</div>';
		html+='</div>';
		YearMenuPanel.innerHTML=html;

		yearPopup.ShowFromNewSource(o);
	}
	this.RenderMonthHeading=function()
	{
		var html=''
		html+='<div class="CalendarMonthHeading">';
		html+=ImageHtml(CalendarRightImg,'CalendarPageImg',id+'.SetRenderMonth('+(this.RenderDate.Month+1)+')',null, null, 'cursor:pointer;float:right;');    
		html+=ImageHtml(CalendarLeftImg,'CalendarPageImg',id+'.SetRenderMonth('+(this.RenderDate.Month-1)+')',null, null, 'cursor:pointer;');    
		html+='</div>';
		return html;
	}
	this.RenderHeading=function()
	{
		var html=''
		html+='<div class="CalendarHeading">';  
		html+=ImageHtml(CloseImg,null, id+'.Hide()', null, null, 'float:right;cursor:pointer;');
		html+='<div id="'+id+'_month_sel" onclick="'+id+'.ShowMonthMenu(this);" style="cursor:pointer;float:left;" class="CalendarMonthSelector">';
		html+=this.MonthNames[this.RenderDate.Month];
		html+='&nbsp;';
		html+=ImageHtml(CalendarDownImg,null,null,null, null, 'cursor:pointer;');
		html+='</div>';
		html+='<span id="'+id+'_year_sel" onclick="'+id+'.ShowYearMenu(this);" style="cursor:pointer;" class="CalendarYearSelector">';
		html+=this.RenderDate.Year;
		html+='&nbsp;';
		html+=ImageHtml(CalendarDownImg,null,null,null, null, 'cursor:pointer;');
		html+='</span>';
		if(!this.Required)
			html+='<span onclick="'+id+'.Clear();" class="CalendarClear" style="cursor:pointer;">Clear</span>'
		html+='</div>';
		return html;
	}
	this.RenderFooter=function()
	{
		var html='';
		html+='<div class="CalendarFooter">';
		html+='<span class="CalendarFooterTitle">Today:&nbsp;</span>';
		var td=this.ConvertDate(today);
		var ids=this.IsDateSelectable(td);
		var click='';
		if(ids.Clickable)
			click=id+'.SetDate('+(td.Day-1)+','+(td.Month-1)+','+td.Year+')';
		html+='<span class="CalendarFooterText" onclick="'+click+'" title="'+ids.Title+'">';
		html+=this.GetFormatString(td);
		html+='</span>';
		html+='</div>';
		return html;
	}
	this.Render=function()
	{
		var html=''
		if(Web.Ajax.Browser=='IE6')
			html+='<iframe frameborder="0" style="width:195px;height:170px;z-index:-1;position:absolute;left:0px;top:0px;border: solid 0px #fff;"></iframe>';              
		html+=this.RenderHeading();
		html+=this.RenderMonthHeading();
		html+=this.RenderMonth();
		html+=this.RenderFooter();
		if(Calendar==null)
			Calendar=Append('div',id+'_Calendar','CalendarPanel');
		Calendar.innerHTML=html;
	}
	this.GetClientHtml=function(tbw)
	{
		var html='';
		html+='<span id="'+id+'_src" >';
		html+='<input type="text" class="DateTextBox" readonly id="'+id+'_tb" onclick="'+id+'.Show();" style="'+(tbw?tbw:'')+'" />';
		html+=ImageHtml(ImageUrl('Calendar.gif'),'DateImage',id+'.Show();');
		html+='</span>'; 
		if (this.Required)
			html+='<img id="' + id + '_val"  src="' + ImageUrl('Failure.gif') + '" class="CalendarValidator" style="visibility:hidden;" title="This is a required field." />'; 

		html+='<input id="' + id + '_value" name="' + id + '_value" type="hidden" style="display:none;" />';
		return html;
	}
	this.Show=function()
	{
		if(this.Disabled)
			return;
		if(this.FirstShow)
		{
			if(this.MinCal)
				this.MinCal=eval(this.MinCal);
			if(this.MaxCal)
				this.MaxCal=eval(this.MaxCal);
			this.FirstShow=false;
		}
		if(CurrentVisibleCalendar)
			CurrentVisibleCalendar.Hide();
		CurrentVisibleCalendar=this;
		var dt=this.Date;
		var rd=new Object();
		if(dt)
		{
			rd.Day=dt.Day-1;        //Convert to 0 based day
			rd.Month=dt.Month-1;    //Convert to 0 based Month
			rd.Year=dt.Year;
		}
		else
		{
			rd.Day=today.getDate();
			rd.Month=today.getMonth();
			rd.Year=today.getFullYear();
			if(this.Follow)
			{
				if(this.MaxCal&&this.MaxCal.Date)
				{
					rd.Month=this.MaxCal.Date.Month-1;
					rd.Year=this.MaxCal.Date.Year;
				}
				if(this.MinCal&&this.MinCal.Date)
				{
					rd.Month=this.MinCal.Date.Month-1;
					rd.Year=this.MinCal.Date.Year;
				}
			}
		}
		this.RenderDate=rd;
		if(!this.StartYear)
			this.StartYear=rd.Year-parseInt(this.YearsInDropDown/2);
		this.Render();
		popup.Show(el(id+'_src'));
	}
	this.Hide=function()
	{
		popup.Hide();
		monthPopup.Hide();
		yearPopup.Hide();
	}
	this.Clear=function()
	{
		this.Date=null;
		ve.value='';
		Textbox.value='';
		this.Hide();
		if(sid)
			SaveSession(sid,null);
		if(this.OnDateChanged)
			eval(this.OnDateChanged);
	}
	this.Enable=function()
	{
		this.Disabled=false;
		Textbox.disabled=false;
	}
	this.Disable=function()
	{
		this.Disabled=true;
		Textbox.disabled=true;
	}
	this.IsValid=function()
	{
		var v=this.Validator;
		if(!v)
		{
			v=new Validator(id+'_val',true);
			v.SourceId=id+'_src';
			if(this.ValidatorType)
				v.Type=this.ValidatorType;
			this.Validator=v;
		}
		v.Hide();
		if(this.Required&&!this.Date&&!this.Disabled)
		{
			v.Show('This is a required field.');
			return false;
		}
		return true;
	}
	this.GetAnswer=function()
	{
		return this.Date;
	}
	this.SetAnswer=function(ans)
	{
		this.Date=ans;
		this.Init();
	}
	if(sid)
	{
		var sd=Session[sid];
		if(sd&&sd.Day&&sd.Month&&sd.Year)
			this.SetDate(sd.Day-1,sd.Month-1,sd.Year,true);
	}
}
FormatDate = function(d, f)
{
	var c = new Calendar();
	if (f)
		c.Format = f;
	return c.GetFormatString(d);
}
FormatDateTime = function(d) {
	var c = new Calendar();
	return c.GetFormatString(d, true);
}
var CurrentVisibleCalendar=null;
